<?php
class jfPortableDevice
{

  const DEVICE_SIZE_S = 1; //small screens
  const DEVICE_SIZE_M = 2; //iPhone & co.
  const DEVICE_SIZE_L = 3; //iPad & co.
  
  const APP_TYPE_WEB = 'web';
  const APP_TYPE_NATIVE = 'native';


  protected static $isPortableDevice = false; //gets activated by jfPortableDeviceFilter
  protected static $appType;
  protected static $deviceSize;
  
  protected static $config;
  
  public static function getConfig($key, $default = null) {
  	if (!self::$config) {
  		self::$config = sfConfig::get('app_jfPortableDevice_config');
  	}

  	if (array_key_exists($key, self::$config)) {
  		return self::$config[$key];
  	}
  	
  	return $default;
  }
  
  public static function setConfig($key, $value, $append = false, $appendSeparator = ' | ') {
  	
  	if ($append) {
  		$existingValue = self::getConfig($key);
  		if (!empty($existingValue)) {
  			$value = $existingValue.$appendSeparator.$value;
  		}
  	}
  	
  	if (!self::$config) {
  		self::$config = sfConfig::get('app_jfPortableDevice_config');
  	}

 		self::$config[$key] = $value;
  }
  
  /**
   * Returns true if the requesting device is recognized as portabel device.
   * You should use this wrapper method insetad of directly querying the device
   * parameter because the parameter or it's values may change over time
   *
   * @return Bool
   */
  public static function isPortableDevice()
  {
    return self::$isPortableDevice;
  }
  public static function setIsPortableDevice($value)
  {
    self::$isPortableDevice = $value;
  }
  
  /**
   * Returns true if the request was triggered in order to "build" the code for deployment on native apps
   *
   * @return Bool
   */
  public static function getAppType()
  {
    if (!isset(self::$appType)) {
      self::setAppType(sfContext::getInstance()->getRequest()->getParameter('jfPD_appType', 'web'));
    }
    return self::$appType;
  }
  public static function setAppType($value)
  {
    if (!in_array($value, array('web', 'native'))) {
      throw new jfPortableDeviceSecurityException('invalid app type');
    }

    self::$appType = $value;
  }
  
  /**
   * Returns true if the request was triggered in order to "build" the code for deployment on native apps
   *
   * @return Bool
   */
  public static function isNativeApp()
  {
    return self::getAppType() === self::APP_TYPE_NATIVE;
  }
  
  
  /**
   * Returns an integer classifying the screen size of the device that 
   * made the current request.
   * 
   * @return int
   */
  public static function getDeviceSize()
  {
    if (!isset(self::$deviceSize)) {
      self::setDeviceSize(sfContext::getInstance()->getRequest()->getParameter('jfPD_size', self::DEVICE_SIZE_M));
    }
    return self::$deviceSize;
  }
  public static function setDeviceSize($value)
  {
    self::$deviceSize = intval($value);
  }
  
  public static function setActiveTab($value) {
  	self::setConfig('activeTab', $value);
  	self::setPageAttribute('data-activeTab', $value);
  }
  public static function getActiveTab($default = null) {
  	return self::getConfig('activeTab', $default);
  }
  
  public static function setPageTitle($value) {
  	self::setConfig('pageTitle', $value);
  }
  public static function getPageTitle($default = null) {
  	if (is_null($default)) {
  		$default = self::getConfig('appTitle');
  	}
  	return self::getConfig('pageTitle', $default);
  }
  
  public static function setPageAttribute($key, $value) {
  	$pageAttributes = self::getConfig('pageAttributes');
  	$pageAttributes[$key] = $value;
  	self::setConfig('pageAttributes', $pageAttributes);
  }
  
  
  /**
   * Remove all jfPortableDevice-specific parameters from the given {@param $url}.
   * 
   * @param String $url
   * @param Boolean $addRedirectStopParameter
   * 
   * @return String
   */
  public static function cleanUrl($url, $addRedirectStopParameter = false) {
  	$urlParsed = parse_url($url);
  	//var_dump($urlParsed); =>  array(4) { ["scheme"]=> string(4) "http" ["host"]=> string(30) "jonasfischer.net" ["path"]=> string(48) "/index.php/cms/about" ["query"]=> string(49) "jfPD_device=portable&jfPD_size=3&jfPD_appType=web" } 
  	
  	$url = '';
  	if (isset($urlParsed['scheme'])) {
  		$url .= $urlParsed['scheme'].'://';
  	}
  	if (isset($urlParsed['host'])) {
  		$url .= $urlParsed['host'];
  	}
  	$url .= $urlParsed['path'];
  	
  	$queryParams = array();
  	if (array_key_exists('query', $urlParsed)) {
  		parse_str($urlParsed['query'], $tmp);
  		//var_dump($tmp); => array(3) { ["jfPD_device"]=> string(8) "portable" ["jfPD_size"]=> string(1) "3" ["jfPD_appType"]=> string(3) "web" }
  		foreach ($tmp as $key => $value) {
  			if (strpos($key, 'jfPD_') === 0) {
  				unset($tmp[$key]);
  			}
  		}
  		$queryParams = $tmp;
  	}
  	
  	
  	if ($addRedirectStopParameter) {
  		$redirectStopParameter = self::getConfig('redirectStopParameter');
  		if ($redirectStopParameter) {
  			$queryParams[$redirectStopParameter] = 1;
  		}
  	}
  	
   	if (!empty($queryParams)) {
  		$url .= '?'.http_build_query($queryParams);
  	}

  	return $url;
  }

  /**
   * Add jfPortableDevice-specific parameters to the given {@param $url}
   * 
   * @param String $url
   * 
   * @return String
   */
  public static function extendUrl($url, $force = false) {
  	if ($force || self::isPortableDevice()) {
	  	$url = self::cleanUrl($url);
	  	
	  	$params = array('jfPD_device' => 'portable', 'jfPD_appType' => self::getAppType(), 'jfPD_size' => self::getDeviceSize());
			$url .= false === strpos($url, '?') ? '?' : '&';
			$url .= http_build_query($params);
  	}

  	return $url;
  }
  
  /**
   * Override method:
   * - force symfony to store distinct cache versions for ajax and non-ajax requests
   * 
   * To enable this feature, add the following setting to your settings.yml:
   * 
   * <pre>
   * jfPortableDevice::symfonyCacheKeyAjaxDistinction
   * </pre>
   * 
   */
	public static function symfonyCacheKeyAjaxDistinction($internalUri, $hostName = '', $vary = '', $contextualPrefix = '', $sfViewCacheManager) {
		//store original callback
    $callableFunction =  sfConfig::get('sf_cache_namespace_callable');
 
    //retrieve original cache key
    sfConfig::set('sf_cache_namespace_callable', false);
    $cacheKey = $sfViewCacheManager->generateCachekey( $internalUri, $hostName = '', $vary = '', $contextualPrefix = '' );
 
    //restore original callback
    sfConfig::set( 'sf_cache_namespace_callable', $callableFunction );
 
    //extend original cache key
    if (sfContext::getInstance()->getRequest()->isXmlHttpRequest()) {
    	$cacheKey .= '_isAjax';
    }

    return $cacheKey;
  }

}